﻿using Microsoft.Crm.Sdk.Messages;
using Microsoft.Pfe.Xrm;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Messages;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace aier.xrm.wcf
{
    public class CommonWcf
    {
        public XrmService xrmService { get; set; }

        /// <summary>
        /// 根据实体id删除实体信息
        /// </summary>
        /// <param name="entityName">实体名称</param>
        /// <param name="id">id</param>
        public void DeleteEntityById(string entityName,Guid id) {
            xrmService.UseOrganizationServiceProxy(_service =>
            {
                _service.Delete(entityName,id);

            });
        }

        /// <summary>
        /// 根据实体ID修改实体信息
        /// </summary>
        /// <param name="entity">实体对像</param>
        /// <returns></returns>
        public void UpdateEntityById(Entity entity)
        {
            xrmService.UseOrganizationServiceProxy(_service=>
            {
                _service.Update(entity);
              
            });
            
        }

        /// <summary>
        /// 根据实体ID修改实体信息,
        /// </summary>
        /// <param name="id">代理ID</param>
        /// <param name="entity">实体对像</param>
        /// <returns></returns>
        public void UpdateEntityProxyById(Guid id, Entity entity)
        {
            xrmService.UseOrganizationServiceProxy(_service =>
            {
                _service.Update(entity);

            },id);

        }

        /// <summary>
        /// 创建实体
        /// </summary>
        /// <param name="entity"></param>
        public Guid CreateEntity(Entity entity)
        {
            Guid guid = Guid.Empty;
            xrmService.UseOrganizationServiceProxy(_service =>
            {
                guid = _service.Create(entity);
            });
            return guid;
        }

        /// <summary>
        /// 通过代理创建实体
        /// </summary>
        /// <param name="id">代理用户ID</param>
        /// <param name="entity">实体对像</param>
        public Guid CreateEntityProxy(Guid id, Entity entity)
        {
            try
            {
                return xrmService.UseOrganizationServiceProxy<Guid>(_service =>
                {
                    return _service.Create(entity);
                }, id);
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                throw ex;
            }
         
        }

        /// <summary>
        /// 获取当前用户ID
        /// </summary>
        /// <param name="uname">用户名</param>
        /// <param name="pwd">密码</param>
        /// <returns></returns>
        public Guid ValidateUser(string uname,string pwd)
        {
            Guid currentUserId = Guid.Empty;

            xrmService.UseOrganizationServiceProxy(uname, pwd, g =>
            {
                WhoAmIRequest whoRequest = new WhoAmIRequest();
                WhoAmIResponse whoResponse = (WhoAmIResponse)g.Execute(whoRequest);
                currentUserId = whoResponse.UserId;
            });

            return currentUserId;
        }

        /// <summary>
        /// 更新系统状态信息带status
        /// </summary>
        /// <param name="id">实体主键</param>
        /// <param name="state">状态</param>
        /// <param name="logicalname">实体名称</param>
        public void UpdateStateRequestWithStatus(Guid id, int state,int status,string logicalname)
        {
            SetStateRequest stateRequest = new SetStateRequest();
            stateRequest.State = new OptionSetValue(state);
            stateRequest.Status = new OptionSetValue(status);
            stateRequest.EntityMoniker = new EntityReference { Id = id, LogicalName = logicalname };
            xrmService.UseOrganizationServiceProxy(_service =>
            {
                _service.Execute(stateRequest);
            });
        }

        /// <summary>
        /// 更新系统状态信息
        /// </summary>
        /// <param name="id">实体主键</param>
        /// <param name="state">状态</param>
        /// <param name="logicalname">实体名称</param>
        public void UpdateStateRequest(Guid id, int state,string logicalname)
        {
            SetStateRequest stateRequest = new SetStateRequest();
            stateRequest.State = new OptionSetValue(state);
            stateRequest.EntityMoniker = new EntityReference { Id = id, LogicalName = logicalname };
            xrmService.UseOrganizationServiceProxy(_service =>
            {
                _service.Execute(stateRequest);
            });
        }

        /// <summary>
        /// 更新系统状态信息
        /// </summary>
        /// <param name="id">实体主键</param>
        /// <param name="state">状态</param>
        /// <param name="state">状态</param>
        /// <param name="logicalname">实体名称</param>
        public void UpdateStateRequest(Guid id, string logicalname, int state,int status)
        {
            SetStateRequest stateRequest = new SetStateRequest();
            stateRequest.State = new OptionSetValue(state);
            stateRequest.Status = new OptionSetValue(status);
            stateRequest.EntityMoniker = new EntityReference { Id = id, LogicalName = logicalname };
            xrmService.UseOrganizationServiceProxy(_service =>
            {
                _service.Execute(stateRequest);
            });
        }

        /// <summary>
        /// 解除关系
        /// </summary>
        /// <param name="primaryEr"></param>
        /// <param name="erList"></param>
        /// <param name="relationshipaName"></param>
        public void ExceDisassociate(EntityReference primaryEr, IEnumerable<EntityReference> erList
            , string relationshipaName) {
            if(primaryEr != null && primaryEr.Id != Guid.Empty)
            {
                xrmService.UseOrganizationServiceProxy(_service =>
                {
                    EntityReferenceCollection relatedEntities = new EntityReferenceCollection(erList.ToList<EntityReference>());
                    Relationship relationship = new Relationship(relationshipaName);
                    _service.Disassociate(primaryEr.LogicalName, primaryEr.Id, relationship, relatedEntities);
                });
            }
         
        }

        /// <summary>
        /// 创建关系
        /// </summary>
        /// <param name="primaryEr">主实体</param>
        /// <param name="erList">副实体列表</param>
        /// <param name="relationshipaName">关系的名称</param>
        public void ExceAisassociateMToMEntities(EntityReference primaryEr, IEnumerable<EntityReference> erList, string relationshipaName)
        {
            if (primaryEr!=null && primaryEr.Id!=Guid.Empty)
            {
                xrmService.UseOrganizationServiceProxy(_service =>
                {
                    var executeMultipleRequest = GetExecuteMultipleRequest();
                    foreach (var er in erList)
                    {
                        var associateEnReq = this.AisassociateMToMEntities(primaryEr, er, relationshipaName);
                        executeMultipleRequest.Requests.Add(associateEnReq);
                    }
                    var excuteMultipleResp = _service.Execute(executeMultipleRequest) as ExecuteMultipleResponse;

                    string erromsg = ExceMulResponseConsoleLog(excuteMultipleResp, executeMultipleRequest,
                        string.Concat(primaryEr.LogicalName, "-", erList.FirstOrDefault()?.LogicalName));
                    if (!string.IsNullOrWhiteSpace(erromsg))
                        throw new Exception(erromsg);
                });
            }
               
        }

        /// <summary>
        /// 批量创建
        /// </summary>
        /// <param name="entities">实体集</param>
        public ExecuteMultipleResponse ExecultMutipleCreate(IEnumerable<Entity> entities,out string res)
        {
            res = string.Empty;
            ExecuteMultipleRequest requestWithResults = null;
            ExecuteMultipleResponse response =
            xrmService.UseOrganizationServiceProxy(_service =>
            {
                 requestWithResults = this.GetExecuteMultipleRequest();

                // Add a CreateRequest for each entity to the request collection.
                foreach (var entity in entities)
                 {
                     CreateRequest createRequest = new CreateRequest { Target = entity };
                     requestWithResults.Requests.Add(createRequest);
                 }
                

                 return (ExecuteMultipleResponse)_service.Execute(requestWithResults);
            });

            res= ExceMulResponseConsoleLog(response, requestWithResults, "new_sc_result");
            return response;
        }

        /// <summary>
        /// 批量更新
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public ExecuteMultipleResponse ExecultMutipleUpdate(IEnumerable<Entity> entities)
        {
            return xrmService.UseOrganizationServiceProxy(_service =>
            {
                ExecuteMultipleRequest requestWithResults = this.GetExecuteMultipleRequest();

                // Add a CreateRequest for each entity to the request collection.
                foreach (var entity in entities)
                {
                    UpdateRequest updateRequest = new UpdateRequest { Target = entity };
                    requestWithResults.Requests.Add(updateRequest);
                }

                return (ExecuteMultipleResponse)_service.Execute(requestWithResults);
            });
        }

        /// <summary>
        /// 批量多线程跟新
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public string[] ExecultParallelUpdateRequst(IEnumerable<Entity> entities)
        {
            IDictionary<string, OrganizationRequest> orgRequstDic = new Dictionary<string, OrganizationRequest>();

            foreach (var entity in entities)
            {
                UpdateRequest updateRequest = new UpdateRequest { Target = entity };
                var updateKeyPair = new KeyValuePair<string, OrganizationRequest>(entity.Id.ToString(), updateRequest);
                orgRequstDic.Add(updateKeyPair);
            }

            return xrmService.UseParallelOrganizationServiceManager(t =>
           {
               var respDic = t.ParallelProxy.Execute(orgRequstDic, (req, error) =>
               {
                   if (error != null) throw error;
               });

               return respDic.Keys.ToArray();
           });


        }


        public Guid[] ExecultParallelMutipleCreate(IEnumerable<Entity> entities)
        {
            IDictionary<string, OrganizationRequest> orgRequstDic = new Dictionary<string, OrganizationRequest>();

            // Add a CreateRequest for each entity to the request collection.
            foreach (var entity in entities)
            {
                CreateRequest createRequest = new CreateRequest { Target = entity };
                var createKeyPair = new KeyValuePair<string, OrganizationRequest>(entity.GetAttributeValue<string>("new_contentid"), createRequest);
                orgRequstDic.Add(createKeyPair);
            }

            return xrmService.UseParallelOrganizationServiceManager(t =>
            {
                var respDic = t.ParallelProxy.Execute(orgRequstDic, (req, error) =>
                {
                    if (error != null) throw error;
                });

                return respDic?.Where(r => (r.Value as CreateResponse) != null).Select(r => (r.Value as CreateResponse).id)?.ToArray();
            });

        }


		public Guid[] ExecultParallelMutipleCreate(IEnumerable<Entity> entities,Guid ownerId)
		{
			IDictionary<string, OrganizationRequest> orgRequstDic = new Dictionary<string, OrganizationRequest>();

			// Add a CreateRequest for each entity to the request collection.
			foreach (var entity in entities)
			{
				CreateRequest createRequest = new CreateRequest { Target = entity };
				
				var createKeyPair = new KeyValuePair<string, OrganizationRequest>(Guid.NewGuid().ToString(), createRequest);
				orgRequstDic.Add(createKeyPair);
			}

			var option = new OrganizationServiceProxyOptions();
			option.CallerId = ownerId;

			return xrmService.UseParallelOrganizationServiceManager(t =>
			{
				var respDic = t.ParallelProxy.Execute(orgRequstDic, option, (req, error) =>
				{
					if (error != null) throw error;
				});

				return respDic?.Where(r => (r.Value as CreateResponse) != null)
                               .Select(r => (r.Value as CreateResponse).id)?.ToArray();
			},ownerId);

		}




		private ExecuteMultipleRequest GetExecuteMultipleRequest(bool ContinueOnError=false)
        {
           return  new ExecuteMultipleRequest()
            {
                // Assign settings that define execution behavior: continue on error, return responses. 
                Settings = new ExecuteMultipleSettings()
                {
                    ContinueOnError = false,
                    ReturnResponses = true
                },
                // Create an empty organization request collection.
                Requests = new OrganizationRequestCollection()
            };
        }

        /// <summary>
        /// 日志
        /// </summary>
        /// <param name="responseWithNoResults"></param>
        /// <param name="executeMultipleRequest"></param>
        public string ExceMulResponseConsoleLog(ExecuteMultipleResponse responseWithNoResults,
                                                     ExecuteMultipleRequest executeMultipleRequest, string entityName)
        {
            StringBuilder errorSb = new StringBuilder();
            foreach (var responseItem in responseWithNoResults.Responses)
            {
                var msg = DisplayFault(executeMultipleRequest.Requests[responseItem.RequestIndex], responseItem.RequestIndex, responseItem.Fault);
                // A valid response.
                if (responseItem.Response != null)
                {
                    //logger.Info(string.Concat("success--", "Entity: ", entityName, "--", msg));
                }
                // An error has occurred.
                else if (responseItem.Fault != null)
                {
                    //logger.Error(msg);
                    errorSb.AppendLine(msg);
                }
            }
            return errorSb.ToString();
        }


        private  string DisplayFault(OrganizationRequest organizationRequest, int count,
           OrganizationServiceFault organizationServiceFault)
        {
            string errormsg = string.Empty;
            if (organizationServiceFault != null)
            {

                errormsg = string.Format("When processing the {1} request, a fault occurred in the index {0} in the request set:{2} ", count + 1,
                      organizationRequest.RequestName, organizationServiceFault.Message);
            }
            else
            {

                errormsg = string.Format("The {1} request is successfully processed, and the index {0} in the request collection ", count + 1,
                      organizationRequest.RequestName);
            }
            return errormsg;
        }


        private AssociateEntitiesRequest AisassociateMToMEntities(EntityReference moniker1, EntityReference moniker2,
            string strEntityRelationshipName)

        {
            AssociateEntitiesRequest request = new AssociateEntitiesRequest();

            // Set the ID of Moniker1 to the ID of the lead.
            request.Moniker1 = new EntityReference { Id = moniker1.Id, LogicalName = moniker1.LogicalName };

            // Set the ID of Moniker2 to the ID of the contact.
            request.Moniker2 = new EntityReference { Id = moniker2.Id, LogicalName = moniker2.LogicalName };

            // Set the relationship name to associate on.
            request.RelationshipName = strEntityRelationshipName;

            return request;
        }

    }
}
